#include "io.hpp"
#include "util.hpp"
#include "serialization.hpp"


void write_seq_call_counts(std::ostream &os, array_type4 &calls)
{

    boost::iostreams::filtering_ostream out;
    out.push(boost::iostreams::gzip_compressor());
    out.push(os);
    boost::archive::binary_oarchive oa(out);
    oa << CALL_RATES_FILE_TYPE;
    oa << CALL_RATES_SEQ_FILE_VERSION;
    oa << calls;
}

void write_seq_call_counts_file(char *fname, array_type4 &calls)
{
    std::ofstream ofs(fname, std::ios_base::binary);
    write_seq_call_counts(ofs, calls);
    ofs.close();
}

void read_seq_call_counts(std::istream &is, array_type4 &calls)
{
    unsigned int ftype, fversion;

    boost::iostreams::filtering_istream in;
    in.push(boost::iostreams::gzip_decompressor());
    in.push(is);

    try
    {
        boost::archive::binary_iarchive ia_call(in);
        ia_call >> ftype;
        ia_call >> fversion;

        if(ftype != CALL_RATES_FILE_TYPE)
            error("File given is not a call rates file");
        if(fversion != CALL_RATES_SEQ_FILE_VERSION)
            error("File given is not the right version of a call rates file.  Was it made with the most recent comb? file: ");
        ia_call >> calls;
    }
    catch(boost::archive::archive_exception &ae)
    {
        error("Could not open call rates file as an archive. archive_exception: " + std::string(ae.what()));
    }
}

void read_seq_call_counts_file(const char *fname, array_type4 &calls)
{
    std::ifstream ifs(fname, std::ios_base::binary | std::ios_base::in);
    if(!ifs)
        error("Could not open file: " + std::string(fname));
    read_seq_call_counts(ifs, calls);
    ifs.close();
}


void write_call_counts(std::ostream &os, array_type5 &calls)
{

    boost::iostreams::filtering_ostream out;
    out.push(boost::iostreams::gzip_compressor());
    out.push(os);
    boost::archive::binary_oarchive oa(out);
    oa << CALL_RATES_FILE_TYPE;
    oa << CALL_RATES_COL_FILE_VERSION;
    oa << calls;
}

void write_call_counts_file(char *fname, array_type5 &calls)
{
    std::ofstream ofs(fname, std::ios_base::binary);
    write_call_counts(ofs, calls);
    ofs.close();
}

void read_call_counts(std::istream &is, array_type5 &calls)
{
    unsigned int ftype, fversion;

    boost::iostreams::filtering_istream in;
    in.push(boost::iostreams::gzip_decompressor());
    in.push(is);

    try
    {
        boost::archive::binary_iarchive ia_call(in);
        ia_call >> ftype;
        ia_call >> fversion;

        if(ftype != CALL_RATES_FILE_TYPE)
            error("File given is not a call rates file");
        if(fversion != CALL_RATES_COL_FILE_VERSION)
            error("File given is not the right version of a call rates file.  Was it made with the most recent comb? file: ");
        ia_call >> calls;
    }
    catch(boost::archive::archive_exception &ae)
    {
        error("Could not open call rates file as an archive. archive_exception: " + std::string(ae.what()));
    }
}

void read_call_counts_file(const char *fname, array_type5 &calls)
{
    std::ifstream ifs(fname, std::ios_base::binary | std::ios_base::in);
    if(!ifs)
        error("Could not open file: " + std::string(fname));
    read_call_counts(ifs, calls);
    ifs.close();
}

void read_snp_cand(std::istream &is, cand_blocks_t &cand_blocks, cand_vector_t &snp_cands)
{
    unsigned int ftype, fversion;
    boost::iostreams::filtering_istream in;
    in.push(boost::iostreams::gzip_decompressor());
    in.push(is);
    try
    {
        boost::archive::binary_iarchive ia_cand(in);
        ia_cand >> ftype;
        ia_cand >> fversion;

        if(ftype != SNP_CAND_FILE_TYPE)
            error("File given is not a SNP candidate file.");
        if(fversion != SNP_CAND_FILE_VERSION)
            error("File given is not the right version.  Was it made with the most recent comb?");
        
        ia_cand >> cand_blocks;
        ia_cand >> snp_cands;
    }
    catch(boost::archive::archive_exception &ae)
    {
        error("Could not open snp candidate file as an archive. archive_exception: " + std::string(ae.what()));
    }
}

void write_expression(std::ostream &os, map_str_vafl_t &expression)
{

    boost::iostreams::filtering_ostream out;
    out.push(boost::iostreams::gzip_compressor());
    out.push(os);
    boost::archive::binary_oarchive oa(out);
    oa << EXPRESSION_FILE_TYPE;
    oa << EXPRESSION_FILE_VERSION;
    oa << expression;
}


void read_snp_cand_file(const char *fname, cand_blocks_t &cand_blocks, cand_vector_t &snp_cands)
{
    std::ifstream ifs(fname, std::ios_base::binary | std::ios_base::in);
    if(!ifs)
        error("Could not open file: " + std::string(fname));
    read_snp_cand(ifs, cand_blocks, snp_cands);
    ifs.close();
}

void write_snp_cand(std::ostream &os, cand_blocks_t &cand_blocks, cand_vector_t &snp_cands)
{
    boost::iostreams::filtering_ostream out;
    out.push(boost::iostreams::gzip_compressor());
    out.push(os);
    boost::archive::binary_oarchive oa(out);
    oa << SNP_CAND_FILE_TYPE;
    oa << SNP_CAND_FILE_VERSION;
    oa << cand_blocks;
    oa << snp_cands;
}

void read_map_count_file(const char *fname, mapping_type &t, map_str_vafl_t &subs, map_str_vafl_t &totl)
{
    std::ifstream ifs(fname, std::ios_base::binary | std::ios_base::in);
    if(!ifs)
        error("Could not open file: " + std::string(fname));
    read_map_count(ifs, t, subs, totl);
    ifs.close();
}


void read_col_snp_call(std::istream &is, bool &diploid, color_call_vector_t &cv)
{
    unsigned int ftype, fversion;
    boost::iostreams::filtering_istream in;
    in.push(boost::iostreams::gzip_decompressor());
    in.push(is);
    boost::archive::binary_iarchive ia(in);
    ia >> ftype;
    ia >> fversion;
    if(ftype != SNP_CALL_COL_FILE_TYPE)
        error("bad file type when reading snp_call file in mergemapcounts.");
    if(fversion != SNP_CALL_COL_FILE_VERSION)
        error("bad file version when reading snp_call file in mergemapcounts.");
    ia >> diploid;
    ia >> cv;
}

void read_col_snp_call_file(const char *fname, bool &diploid, color_call_vector_t &cv)
{
    std::ifstream ifs(fname, std::ios_base::binary | std::ios_base::in);
    if(!ifs)
        error("Could not open file: " + std::string(fname));
    read_col_snp_call(ifs, diploid, cv);
    ifs.close();
}

void read_seq_snp_call(std::istream &is, bool &diploid, seq_call_vector_t &cv)
{
    unsigned int ftype, fversion;
    boost::iostreams::filtering_istream in;
    in.push(boost::iostreams::gzip_decompressor());
    in.push(is);
    boost::archive::binary_iarchive ia(in);
    ia >> ftype;
    ia >> fversion;
    if(ftype != SNP_CALL_SEQ_FILE_TYPE)
        error("bad file type when reading snp_call file in mergemapcounts.");
    if(fversion != SNP_CALL_SEQ_FILE_VERSION)
        error("bad file version when reading snp_call file in mergemapcounts.");
    ia >> diploid;
    ia >> cv;
}

void read_seq_snp_call_file(const char *fname, bool &diploid, seq_call_vector_t &cv)
{
    std::ifstream ifs(fname, std::ios_base::binary | std::ios_base::in);
    if(!ifs)
        error("Could not open file: " + std::string(fname));
    read_seq_snp_call(ifs, diploid, cv);
    ifs.close();
}


void read_map_count(std::istream &is, mapping_type &t, map_str_vafl_t &subs, map_str_vafl_t &totl)
{
    unsigned int ftype, fversion;
    boost::iostreams::filtering_istream in;
    in.push(boost::iostreams::gzip_decompressor());
    in.push(is);
    boost::archive::binary_iarchive ia(in);
    ia >> ftype;
    ia >> fversion;
    if(ftype != SUBS_TOTL_FILE_TYPE)
        error("bad file type when reading subs_totl file in mergemapcounts.");
    if(fversion != SUBS_TOTL_FILE_VERSION)
        error("bad file version when reading subs_totl file in mergemapcounts.");
    ia >> t;
    ia >> subs;
    ia >> totl;
}

void write_map_count(std::ostream &os, mapping_type &t, map_str_vafl_t &subs, map_str_vafl_t &totl)
{
    boost::iostreams::filtering_ostream out;
    out.push(boost::iostreams::gzip_compressor());
    out.push(os);
    boost::archive::binary_oarchive oa(out);
    oa << SUBS_TOTL_FILE_TYPE;
    oa << SUBS_TOTL_FILE_VERSION;
    oa << t;
    oa << subs;
    oa << totl;
}

void write_col_snp_call(std::ostream &os, bool diploid, color_call_vector_t &cv)
{
    boost::iostreams::filtering_ostream out;
    out.push(boost::iostreams::gzip_compressor());
    out.push(os);
    boost::archive::binary_oarchive oa(out);
    oa << SNP_CALL_COL_FILE_TYPE;
    oa << SNP_CALL_COL_FILE_VERSION;
    oa << diploid;
    oa << cv;
}

void write_seq_snp_call(std::ostream &os, bool diploid, seq_call_vector_t &cv)
{
    boost::iostreams::filtering_ostream out;
    out.push(boost::iostreams::gzip_compressor());
    out.push(os);
    boost::archive::binary_oarchive oa(out);
    oa << SNP_CALL_SEQ_FILE_TYPE;
    oa << SNP_CALL_SEQ_FILE_VERSION;
    oa << diploid;
    oa << cv;
}
